package com.risen.project.common;

import java.util.concurrent.*;

/**
 * 通用线程池
 */
public class CommonThreadPool {

    private volatile static ExecutorService executorService = null;

    /**
     * @coder taoym
     * @datetime 2021/3/25 9:53
     * @desc 获取单例的线程池
     */
    public static ExecutorService getExecutorService() {
        if (executorService == null) {
            synchronized (CommonThreadPool.class) {
                if (executorService == null) {
                    executorService = createThreadPool(Runtime.getRuntime().availableProcessors()
                            , Runtime.getRuntime().availableProcessors()
                            , 1000
                            , new ThreadPoolExecutor.CallerRunsPolicy());
                }
            }
        }
        return executorService;
    }

    /**
     * 自定义线程池的实现 总体逻辑就是 前corePoolSize个任务时，来一个任务就创建一个线程
     * 如果当前线程池的线程数大于了corePoolSize那么接下来再来的任务就会放入到我们上面设置的workQueue队列中
     * 如果此时workQueue也满了，那么再来任务时，就会新建临时线程，那么此时如果我们设置了keepAliveTime或者设置了allowCoreThreadTimeOut，那么系统就会进行线程的活性检查，一旦超时便销毁线程
     * 如果此时线程池中的当前线程大于了maximumPoolSize最大线程数，那么就会执行我们刚才设置的handler拒绝策略
     *
     * @param corePoolSize    常驻核心线程，线程池初始化的时候池里是没有线程的，前面 corePoolSize 个任务是会创建线程，
     *                        当前线程池中的数量大于常驻核心线程数的时候，如果有空闲的线程则使用，没有的话就把任务放到
     *                        工作队列中
     * @param maximumPoolSize 线程池允许创建的最大线程数，如果队列满了，且线程数小于最大线程数，则新建临时线程（空闲超过时间会被销毁的），
     *                        如果队列为无界队列，则该参数无用
     * @param workQueueSize   工作队列，请求线程数大于常驻核心线程数的时候，将多余的任务放到工作队列
     * @param handler         线程池拒绝策略，当线程池和队列都满了，则调用该策略，执行具体的逻辑
     */
    private static ExecutorService createThreadPool(int corePoolSize, int maximumPoolSize, int workQueueSize, RejectedExecutionHandler handler) {
        BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(workQueueSize);
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 60L, TimeUnit.SECONDS, queue, handler);
    }
}
